//=========================================================================
// Copyright (C) 2025 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/select.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <syslog.h>
#include <inttypes.h>
#include <stdint.h>
#include <fcntl.h>
#include "zmtp.h"
#include "int64.h"
#include "lamport_clock.h"
#include "math_utils.h"
#include "checksum.h"
#include "voter_message.h"
#include "voter_lib.h"
#include "voter_server.h"
#include "ZMQ_Switcher.h"
#include "voter_logger.h"
#include "config.h"
#include "rudp.h"
#include "voter_VotingAlgorithms.h"
#include "voter_customized.h"
#include "voter_monitor.h"
#ifdef SYNC_WITH_PHXPAXOS
#include "PhxPaxosC.h"
#endif
#include "DataFrames.h"

extern ChatState *p_Chat;
extern Rudp rudp;
extern LamportClock g_LamportClock;
#define max(a,b) ((a) >= (b) ? (a) : (b))

static int g_pipefd[2];

void set_FD_SET(fd_set *readfds)
{
    /**
     * fd_set 是一个用于描述文件描述符（file descriptor）集合的数据类型，用于在
     * I/O 多路复用中使用。在 fd_set 中，每个 bit 代表一个文件描述符是否
     * 可读/可写/异常等。
     *
     * fd_set 变量的大小由宏 FD_SETSIZE 定义，这通常是操作系统能够支持的最大文件
     * 描述符数。因此，如果你想声明一个大小为 1024 的 fd_set 变量，需要确保宏
     * FD_SETSIZE 的值大于或等于 1024。
     *
     * 在 POSIX 系统上，通常 FD_SETSIZE 的默认值为 1024
     */
    FD_ZERO(readfds);

    /**
     * When we want to be notified by select() that there is
     * activity? If the listening socket has pending clients to accept
     * or if any other client wrote anything.
     */
    FD_SET(p_Chat->serversock, readfds);
    FD_SET(p_Chat->serversockUdp, readfds);
    FD_SET(g_pipefd[0], readfds);
    if (p_Chat->monitorsockUdp > 0) {
        FD_SET(p_Chat->monitorsockUdp, readfds);
    }

    for (int j = 0;  j <= p_Chat->max_client_fd;  j++) {
        if (p_Chat->clients[j].fd > 0) {
            FD_SET(p_Chat->clients[j].fd, readfds);
        }
    }
}

/**
 * Handles new connection requests.
 *
 * Check if a new client is trying to connect, accept,
 * verify IP against a whitelist, and init the client's data if valid.
 *
 * @param readfds A pointer to fd set that are ready for reading.
 * @return        0 == processing is successful, or no new connections
 *                1 == whitelist check fails
 *                2 == client creation fails
 */
int handle_new_connection(fd_set *readfds)
{
    // New TCP client connections pending to accept
    if (FD_ISSET(p_Chat->serversock, readfds)) {
        struct sockaddr_in sa;
        int fd = AcceptClient(p_Chat->serversock, &sa);
        char client_ip[INET_ADDRSTRLEN];

        // Get the sender's IP address and port
        inet_ntop(AF_INET, &sa.sin_addr, client_ip, sizeof(client_ip));
        int client_port = ntohs(sa.sin_port);

        // Check if the client's IP is in the whitelist
        int inNodeWhiteList = InNodeWhiteListCheck(client_ip, client_port);
        if (inNodeWhiteList < 0) {
            printf("client IP is not in whitelist\n");
            g_pVoterRunningState->notInWhiteListIP++;
            close(fd);

            return 1;   // (=continue;)
        }

        // Create a new client object for the connection
        VoterClient *c = CreateClient(fd, &sa);
        if (NULL == c) {
            syslog(LOG_ERR, "CreateClient() error");
            close(fd);

            return 2;   // (=continue;)
        }

        if (g_numNodeWhiteList > 0) {
            strZcpy(c->idVoter, g_pNodeWhiteList[inNodeWhiteList].id, sizeof(c->idVoter));
        }
        else {
            strZcpy(c->idVoter, "all", MAX_ID_SIZE);
        }

        // Welcome the new client, send the signature of comm protocol
        WelcomeToServer(c);

        // Set ZMTP ready to handle the connection
        c->idxDealer = zmtp_voter_listen(-1, fd);
    }

    return 0;
}

int handle_phxpaxos_data(uint64_t idTransaction)
{
#ifdef SYNC_WITH_PHXPAXOS
    Transaction *trans;

    int32_t trans_idx = GetTransIdx(idTransaction);
    if ((trans_idx >= 0) && (trans_idx < MAX_NUM_TRANS)) {
        trans = &(p_Chat->trans_arr[trans_idx]);
    }
    else {
        syslog(LOG_ERR, "handle_phxpaxos_data. GetTransIdx: %d", trans_idx);
#ifdef __DBEUG__
        printf("handle_phxpaxos_data. GetTransIdx: %d\n", trans_idx);
#endif
        return -1;
    }

    if ((VOTING_NULL == trans->votingResult) ||
                                     (VOTING_PASS == trans->votingResult)) {
        // sync voting result to other Voter
        int32_t action = 0x1111;    // ComoPhxUtils::LevelDbWrite;
        char    bufTmp[1];
        size_t  bufTmpSize = 0;
        int     iRet;
        int16_t vr = trans->votingResult;

        // VR = Voting Result
        char   idVoterBuf[MAX_ID_SIZE + 64];
        snprintf(idVoterBuf, sizeof(idVoterBuf), MACRO_VR_PRINTF_FMTSTR,
                                           g_pconfig->id, trans->idTransaction);
        /**
         * 表决结果只同步出去通过与否就行，因为得到表决结果的节点自身一定是参与了
         * 表决的，即有原始数据的
         */
        if ('p' == g_pconfig->cDataSynchronizationProtocol) {
            iRet = PhxPropose(g_oPaxosServer, action, idVoterBuf,
                                   (char*)&vr, sizeof(vr), bufTmp, &bufTmpSize);
        }
        else {
            iRet = PhxProposeDirectly(g_oPaxosServer, action, idVoterBuf,
                                                        (char*)&vr, sizeof(vr));
        }
        if (0 != iRet) {
            syslog(LOG_ERR, "PhxPropose Voting Result failed. iRet: %d", iRet);
            return -2;
        }
    }
#else
    (void)idTransaction;
#endif

    return 0;
}

int handle_udp_data(fd_set *readfds)
{
    // New UDP client connections pending to accept
    if (FD_ISSET(p_Chat->serversockUdp, readfds)) {
        // Since readbuf is defined here as a local variable,
        // We don't need to define a global variable msg_recv like rudp/test/server.c did
        char readbuf[MAX_VoterMessage_SIZE];
        char buffer[MAX_VoterMessage_SIZE];
        struct sockaddr_in sa;
        socklen_t addr_len = sizeof(sa);

        int recv_len = recvfrom(p_Chat->serversockUdp, readbuf,
                      sizeof(readbuf) - 1, 0, (struct sockaddr*)&sa, &addr_len);
        if (recv_len < 0) {
            return 1;       // (=continue;)
        }

        // Display received message info
#ifdef __DBEUG__
        printf("Received UDP data (len=%d)\n", recv_len);
#endif
        //print_hex(readbuf, recv_len);

        VoterMessage *box;

        if (0 != g_pconfig->udp_data_in_raw_mode) {
            uint64_t lamportClock = get_time(&g_LamportClock);
            uint64_t tmpId;
#if 1
            struct DataFrame_TKY_1 *frame = (struct DataFrame_TKY_1 *)readbuf;
            tmpId = (uint64_t)frame->id_in_Fscp;
#else
    #ifdef SYNC_WITH_PHXPAXOS
            /**
             * 在 PhxPaxos 中：
             *     Propose 用的是当前的 InstanceID；
             *     共识完成后，InstanceID 才会 +1，进入下一个槽位。
             */
            tmpId = PhxGetInstanceID(g_oPaxosServer);
    #else
            tmpId = p_Chat->cur_idTransaction;
    #endif
#endif
            box = BoxVoterMessage(buffer,
                                    MAX_VoterMessage_SIZE,      // bufSize
                                    VOTER_CMD_VOTING_BIGDATA,   // type
                                    tmpId,                      // idTransaction
                                    lamportClock,               // lamportClock
                                    0,
                                    readbuf,
                                    recv_len);

            if (NULL == box) {
#ifdef __DBEUG__
                printf("BoxVoterMessage() failed.\n");
#endif
                return false;
            }

        }
        else {
            box = (VoterMessage *)(readbuf + 3);
            if (NULL != CheckBoxVoterMessage(box, recv_len)) {
#ifdef __DBEUG__
                printf("CheckBoxVoterMessage failed\n");
#endif
                return false;
            }

            // RUDP processing
            RudpUpdate(&rudp, readbuf, recv_len, 1);
#ifdef __DBEUG__
            dump_recv(&rudp); // includes RudpRecv()
#endif
        }

#ifdef __DBEUG__
        // Display unpacked VoterMessage info
        printf("handle_udp_data() p_Chat->cur_trans_id %d:\n", p_Chat->cur_trans_id);
        printVoterMessage(box);
#endif

        // Get the sender's IP address and port
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &sa.sin_addr, client_ip, sizeof(client_ip));
        int client_port = ntohs(sa.sin_port);

        // Check if the client's IP is in the whitelist
        int pos = InNodeWhiteListCheck(client_ip, client_port);
        if (pos < 0) {
            syslog(LOG_ERR, "client IP (%s:%d) not in whitelist", client_ip, client_port);
#ifdef __DBEUG__
            printf("client IP (%s:%d) not in whitelist", client_ip, client_port);
#endif
            g_pVoterRunningState->notInWhiteListIP++;

            // 生命不息，工作不止
            return 2; // (=continue;)
        }

        // Find the client
        int j;
        for (j = 0;  j <= p_Chat->numclients;  j++) {
            if ((strcmp(client_ip, p_Chat->clients[j].client_ip) == 0) &&
                              (p_Chat->clients[j].client_port == client_port)) {
                break;
            }
        }

        VoterClient *c;
        if (j <= p_Chat->numclients) {
            c = &(p_Chat->clients[j]);
        }
        else {
            for (j = 0;  j < MAX_CLIENTS;  j++) {
                if (-1 == p_Chat->clients[j].fd) {
                    break;
                }
            }

            // When num of clients reaches limit, the creation fails
            if (j >= MAX_CLIENTS) {
                syslog(LOG_ERR, "Num of clients reaches limit, fails. IP (%s:%d)",
                                                            client_ip, client_port);
                return 3;
            }
            else {
                c = &(p_Chat->clients[j]);
                strZcpy(c->client_ip, client_ip, INET_ADDRSTRLEN);
                if (g_numNodeWhiteList > 0) {
                    strZcpy(c->idVoter, g_pNodeWhiteList[pos].id, MAX_ID_SIZE);
                }
                else {
                    strZcpy(c->idVoter, "all", MAX_ID_SIZE);
                }
                c->client_port = client_port;

                // Set fd = 0 for UDP clients
                c->fd = 0;

                p_Chat->numclients++;
            }
        }

        // Update the last access time of the port
        clock_gettime(CLOCK_REALTIME, &(c->lastAccessTime));
        if (ProcessProtocol(box, box->len, j, true) < 0) {
            g_pVoterRunningState->crcErrorUdp++;
            WriteLog("error, ProcessProtocol, UDP\n", -1);
        }
    }

    return 0;
}

void handle_client_data(fd_set *readfds)
{
    /**
     * Here for each connected client, check if there are pending
     * data the client sent us.
     */
    char readbuf[MAX_VoterMessage_SIZE];

    for (int j = 0;  j <= p_Chat->max_client_fd;  j++) {
        VoterClient *c = &(p_Chat->clients[j]);

        // 查看文件句柄是否被设置了
        if ((c->fd < 0) || (! FD_ISSET(c->fd, readfds))) {
            continue;
        }

        // Update the last access time of the port
        clock_gettime(CLOCK_REALTIME, &(c->lastAccessTime));

        VoterMessage *message = (VoterMessage *)readbuf;
        int str_len = 0;

        if (c->idxDealer >= 0) {
            // ZMQ socket
            if (NULL == zmtp_voter_recv(c->idxDealer, readbuf, sizeof(readbuf))) {
                continue;
            }
        }
        else {
            // Read <sizeof(VoterMessage)> Bytes
            // Read until reaching the end, to avoid reading incomplete message
            int nread = ReadNBytes(c->fd, readbuf, sizeof(VoterMessage) - sizeof(message->buf));
            str_len = message->len - (sizeof(VoterMessage) - sizeof(message->buf));

            // Error or short read means that the socket was closed
            if (nread < (int)(sizeof(VoterMessage) - sizeof(message->buf))) {
                syslog(LOG_ERR, "Disconnected client fd=%d", c->fd);
                FreeClient(j);
                continue;
            }

            // If more in buf, we read more
            if (str_len > 0) {

                // nread_add == length of additionally read
                int nread_add = ReadNBytes(c->fd, readbuf +
                          sizeof(VoterMessage) - sizeof(message->buf), str_len);

                // Error or short read means that the socket was closed
                if (nread_add < str_len) {
                    syslog(LOG_ERR, "Disconnected client fd=%d", j);
                    FreeClient(j);
                    continue;
                }
                nread += nread_add;
            }

            // Display received VoterMessage info
            //printf("Read %d bytes:\n", nread);
            //print_hex(readbuf, nread);
            //printVoterMessage(message);
#ifdef __DBEUG__
            printVoterMsg("handle_client_data", message);
#endif
        }

        // Process the message
        if (ProcessProtocol(message, message->len, j, true) < 0) {
            g_pVoterRunningState->crcErrorTcp++;
            WriteLog("ProcessProtocol() error (TCP)\n", -1);
        }

        // Clear the str buffer
        if (str_len > 0) {
            memset(readbuf + sizeof(VoterMessage) - sizeof(message->buf), 0, str_len);
        }
    }
}

/**
 * Handle timer, ensuring the timing accuracy is within an acceptable range.
 *
 * @param currentTime Point to current time to calculate the pause duration
 * @param delayTime   Point to the accumulated delay time,
 *                    used to check if the delay error is too large
 * @return  True if the timing is accurate
 *
 * Note:
 * 1. Function similar to a timer, pause for a period (VOTING_CYCLE_NANOSECONDS)
 * 2. Timing errors are not allowed to accumulate,
 *    hence the need to check if the timing error is too large.
 */
bool handle_timer(struct timespec *currentTime, int64_t *delayTime)
{
    /**
     * 1.相当于定时器，sleep一段时间(VOTING_CYCLE_NANOSECONDS)
     * 2.计时误差不被传递，所以要判断计时误差是否过大
     *
     * NANOSECONDS_FOR_SCHEDULE * 8, 用来判断其它表决器工作情况的时间 + 本节点自己做表决的时间
     */
    int iRet = TimespecWaitNanoseconds(currentTime, delayTime,
                                       g_pconfig->nanoSecondsVOTING_CYCLE -
                                                  NANOSECONDS_FOR_SCHEDULE * 8);
    // Timing error is too large
    if ((iRet < 0) || (*delayTime > MAX_DELAY_ERROR_NS)) {
        g_pVoterRunningState->countExcessiveTimingError++;
        g_pVoterRunningState->maxExcessiveTimingErrorNs =
                    max(g_pVoterRunningState->maxExcessiveTimingErrorNs, *delayTime);
        WriteLog("Excessive timing error", -1);
        syslog(LOG_ERR, "Timing inaccurate, delayTime =  %ld ns", *delayTime);

        return false;
    }
#ifdef __DBEUG__RT_delayTime
    char buffer[32];
    TimespecToString(buffer, 32, currentTime);
    printf("[%s]RT_delayTime: %ld ns\n", buffer, *delayTime);
#endif
    return true;
}

void notify_select_exit(uint64_t idTransaction)
{
    write(g_pipefd[1], &idTransaction, sizeof(idTransaction));  // 触发 select 退出
}

/**
 * The main() function implements the main chat logic:
 * 1. Accept new clients connections if any.
 * 2. Check if any client sent us some new message.
 * 3. Send the message to all the other clients.
 */
int voting_main(void)
{
    pipe(g_pipefd);
    // 设置非阻塞
    int flags = fcntl(g_pipefd[0], F_GETFL, 0);
    fcntl(g_pipefd[0], F_SETFL, flags | O_NONBLOCK);

    fd_set readfds;
    struct timeval tv;
    int retval;
    int iRet;

    Rudp *U = RudpNew(&rudp, 1, 5); // For now U is not in use
    if (NULL == U) {
        return -1;
    }

    InitVoter();

#ifdef VOTER__SUPPORT_ZMTP
    zmtp_voter_env_init();
#endif

    InitLamportClock(&g_LamportClock);

    while (true) {
        set_FD_SET(&readfds);

        // Set a timeout for select()
        tv.tv_sec = 5;      // timeout 5s
        tv.tv_usec = 0;

        // The arg of select() is max fd + 1.
        // get max fd
        int maxfd = p_Chat->max_client_fd;
        maxfd = max(maxfd, p_Chat->serversock);
        maxfd = max(maxfd, p_Chat->serversockUdp);
        maxfd = max(maxfd, g_pipefd[0]);
        if (p_Chat->monitorsockUdp > 0) {
            maxfd = max(maxfd, p_Chat->monitorsockUdp);
        }

        /**
         * select函数的阻塞和非阻塞由最后一个参数timeout超时时间决定：
         * | timeout | select |                    说明                    |
         * |---------|--------|-------------------------------------------|
         * |   NULL  |  阻塞   | 一直等待FD_SET中某个fd变化(时间=inf)          |
         * |    0    | 非阻塞  | 不阻塞，直接返回(0, 无变化;>0, 有变化)         |
         * |   >0    |  阻塞   | 等待FD_SET中某个fd变化(时间=timeout)，超时返回 |
         */
        retval = select(maxfd + 1, &readfds, NULL, NULL, &tv);

        if (-1 == retval) {
            syslog(LOG_ERR, "select() error");
            // 生命不息，工作不止
            continue;
        }
        else if (0 == retval) {
            /**
             * No FD is ready during the timeout period
             * In the future, this section can be used for periodic wake-ups
             * (even if there is no client activity)
             */
            CleanIdleClient();
            continue;
        }

        if (FD_ISSET(g_pipefd[0], &readfds)) {
            uint64_t idTransaction;
            ssize_t i64Ret;

            // There could be more data in pipe, max number is 100.
            for (int i = 0;  i < 100;  i++) {
                i64Ret = read(g_pipefd[0], &idTransaction, sizeof(idTransaction));
                if (i64Ret >= (ssize_t)sizeof(idTransaction)) {
                    handle_phxpaxos_data(idTransaction);
                }
                else if (errno != EAGAIN) {
                    break;
                }
            }
        }

        if ((p_Chat->monitorsockUdp > 0) &&
                                    FD_ISSET(p_Chat->monitorsockUdp, &readfds)) {
            char readbuf[MAX_VoterMessage_SIZE];
            ssize_t i64Ret;

            i64Ret = read(p_Chat->monitorsockUdp, readbuf, sizeof(readbuf));
            if (i64Ret > 0) {
                VoterMonitorFun(readbuf, i64Ret);
            }
        }

        // There is FD ready, judge:
        // 1. There is a new connection
        iRet = handle_new_connection(&readfds);
        if ((0 == iRet) || (1 == iRet)) {
            ;
        }

        // 2. There is UDP data
        iRet = handle_udp_data(&readfds);
        if (iRet != 0) {
            ;
        }

        // 3. There is TCP data
        handle_client_data(&readfds);

    } // end of while

    return 0;
} // end of voting_main

int process_cur_data_clean(void)
{
    p_Chat->cur_trans_id = 0;

    for (int i = 0;  i < MAX_NUM_TRANS;  i++) {
        for (int32_t j = 0;  j < MAX_CLIENTS;  j++) {
            p_Chat->trans_arr[i].dataState[j] = DATA_NULL;
        }
        p_Chat->trans_arr[i].votingResult = VOTING_NULL;

#ifdef SYNC_WITH_PHXPAXOS
        for (int j = 0;  j < p_Chat->cur_numVoters;  j++) {
            char keybuf[MAX_ID_SIZE + 64];

            snprintf(keybuf, sizeof(keybuf), MACRO_VR_PRINTF_FMTSTR,
                           p_Chat->idVoters[j], p_Chat->trans_arr[i].idTransaction);
            // 尝试性删除表决结果信息（VResult#--#--），不用判断返回值
            (void)PhxLevelDbDelete(keybuf);
        }
#endif
    }

    return 0;
}

int process_data_clean(void)
{
    p_Chat->cur_trans_id = 0;

    for (int32_t i = 0;  i < MAX_CLIENTS;  i++) {
        p_Chat->trans_arr[0].dataState[i] = DATA_NULL;
    }
    p_Chat->trans_arr[0].votingResult = VOTING_NULL;

#ifdef SYNC_WITH_PHXPAXOS
    for (int i = 0;  i < p_Chat->cur_numVoters;  i++) {
        char keybuf[MAX_ID_SIZE + 64];

        snprintf(keybuf, sizeof(keybuf), MACRO_VR_PRINTF_FMTSTR,
                       p_Chat->idVoters[i], p_Chat->trans_arr[0].idTransaction);
        // 尝试性删除表决结果信息（VResult#--#--），不用判断返回值
        (void)PhxLevelDbDelete(keybuf);
    }
#endif

    return 0;
}

int process_all_data_clean(void)
{
    for (int i = 0;  i < MAX_NUM_TRANS;  i++) {
        Transaction *trans = &(p_Chat->trans_arr[i]);

        for (int32_t j = 0;  j < MAX_CLIENTS;  j++) {
            trans->dataState[j] = DATA_NULL;
        }
        trans->votingResult = VOTING_NULL;

#ifdef SYNC_WITH_PHXPAXOS
        for (int j = 0;  j < p_Chat->cur_numVoters;  j++) {
            char keybuf[MAX_ID_SIZE + 64];

            snprintf(keybuf, sizeof(keybuf), MACRO_VR_PRINTF_FMTSTR,
                                     p_Chat->idVoters[j], trans->idTransaction);
            // 尝试性删除表决结果信息（VResult#--#--），不用判断返回值
            (void)PhxLevelDbDelete(keybuf);
        }
#endif
    }

    p_Chat->current_data_num = 0;

    return 0;
}

int process_all_data_check_clean(void)
{
    struct timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);

    for (int i = 0;  i < MAX_NUM_TRANS;  i++) {
        Transaction *trans = &(p_Chat->trans_arr[i]);
        int64_t time_ms;

        time_ms = now.tv_sec * 1000000 + now.tv_nsec / 1000 -
                              //123456                              123456
                                    (trans->establishTime.tv_sec * 1000000 +
                                    trans->establishTime.tv_nsec / 1000);

        if (time_ms < g_pconfig->nanoSecondsVOTING_CYCLE) {
            continue;
        }

        for (int32_t j = 0;  j < MAX_CLIENTS;  j++) {
            trans->dataState[j] = DATA_NULL;
        }
        trans->votingResult = VOTING_NULL;

#ifdef SYNC_WITH_PHXPAXOS
        for (int j = 0;  j < p_Chat->cur_numVoters;  j++) {
            char keybuf[MAX_ID_SIZE + 64];

            snprintf(keybuf, sizeof(keybuf), MACRO_VR_PRINTF_FMTSTR,
                                     p_Chat->idVoters[j], trans->idTransaction);
            // 尝试性删除表决结果信息（VResult#--#--），不用判断返回值
            (void)PhxLevelDbDelete(keybuf);
        }
#endif
    }

    return 0;
}

/**
 * GetTransIdx by idTransaction
 */
int32_t GetTransIdx(uint64_t idTransaction)
{
    for (int32_t i = 0;  i < MAX_NUM_TRANS;  i++) {
        if (p_Chat->trans_arr[i].idTransaction == idTransaction) {
            return i;
        }
    }

    return -1;
}

/**
 * ValidIdTransaction
 */
bool ValidIdTransaction(uint64_t idTransaction)
{
    (void)idTransaction;

    return true;
}

/**
 * The voting_voter_main() function
 */
int voting_voter_main(void)
{
    struct timespec currentTime;
    int64_t delayTime;

    if (MORE_IN_ONE_OUT_WITH_SYNC == g_Voter_Working_Mode) {
        clock_gettime(CLOCK_MONOTONIC, &currentTime);

        do {
            if (! handle_timer(&currentTime, &delayTime)) {
                // continue;
            }
            process_vote();
            process_cur_data_clean();
        } while (true);
    }
    else if (MORE_IN_ONE_OUT_AT_ONCE_WITH_SYNC == g_Voter_Working_Mode) {
    // 弱周期性，周期内的多个事务只是表决池，是为了表决事务对齐用的，一个表决周期内未完成的事务，将被定期清理
        clock_gettime(CLOCK_MONOTONIC, &currentTime);

        do {
            if (! handle_timer(&currentTime, &delayTime)) {
                // continue;
            }

            if (0 != g_pconfig->WeaklyPeriodic) {
                process_all_data_check_clean();
            }
        } while (true);
    }

    else if ((MULTI_IN_MULTI_OUT_PERIODIC_WITH_SYNC == g_Voter_Working_Mode) ||
             (MULTI_IN_ONE_BY_ONE_OUT_PERIODIC == g_Voter_Working_Mode)) {
    // 强周期性，一个表决周期内未表决成功的事务，将引起持别处理
        clock_gettime(CLOCK_MONOTONIC, &currentTime);

        do {
            if (! handle_timer(&currentTime, &delayTime)) {
                // continue;
            }
            process_all_data_clean();
        } while (true);
    }

    return 0;
}
